package com.zhangchenhui.powerMock;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest({EmployeeService.class,EmployeeUtils.class,EmployeeDao.class,FinalEmployeeDao.class})
public class EmployeeServiceTest3 {

    @Test
    public void testGetEmployeeCountWithMock() {
        PowerMockito.mockStatic(EmployeeUtils.class);
        when(EmployeeUtils.getEmployeeCount()).thenReturn(10);
        final EmployeeService employeeService = new EmployeeService();
        int count = employeeService.getEmployeeCount3();
        assertEquals(10, count);
    }

    @Test
    public void testCreateEmployeeWithMock() {
        try {
            PowerMockito.mockStatic(EmployeeUtils.class);
            Employee employee = new Employee();
            when(EmployeeUtils.nextInt(10)).thenReturn(7);
           // PowerMockito.doNothing().when(EmployeeUtils.class);
            assertEquals(7, EmployeeUtils.nextInt(10));
            final EmployeeService employeeService = new EmployeeService();
            employeeService.createEmployee3(employee);
        } catch (Exception e) {
            fail();
        }
    }

    @Test
    public void testSaveOrUpdateCountLessZero() {
        try {
            EmployeeDao employeeDao =
                    mock(EmployeeDao.class);
            whenNew(EmployeeDao.class).withNoArguments()
                    .thenReturn(employeeDao);
            Employee employee = new Employee();
            when(employeeDao.getCount(employee)).thenReturn(0L);
            EmployeeService employeeService = new EmployeeService();
            employeeService.saveOrUpdate(employee);
            Mockito.verify(employeeDao).saveEmployee(employee);
            Mockito.verify(employeeDao, Mockito.never())
                    .updateEmploye(employee);
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
    }

    @Test
    public void testSaveOrUpdateCountMoreThanZero() {
        EmployeeDao employeeDao = mock(EmployeeDao.class);
        try {
            whenNew(EmployeeDao.class).withNoArguments()
                    .thenReturn(employeeDao);
            Employee employee = new Employee();
            when(employeeDao.getCount(employee)).thenReturn(1L);
            EmployeeService employeeService = new EmployeeService();
            employeeService.saveOrUpdate(employee);
            Mockito.verify(employeeDao).updateEmploye(employee);
            Mockito.verify(employeeDao,
                    Mockito.never()).saveEmployee(employee);
        } catch (Exception e) {
            fail();
        }
    }

    @Test
    public void test() {
        FinalEmployeeDao employeeDao = mock(FinalEmployeeDao.class);
        Employee employee = new Employee();
        PowerMockito.doNothing().when(employeeDao).addEmployee(any());
        EmployeeService employeeService = new
                EmployeeService(employeeDao);
        employeeService.createFinalEmployee(employee);
        Mockito.verify(employeeDao).addEmployee(employee);
    }


    @Test
    public void testGetEmail() {
        EmployeeService employeeService = mock(EmployeeService.class);
        when(employeeService
                .findEmailByUserName(Mockito.argThat(new ArgumentMatcher<String>() {
                    @Override
                    public boolean matches(String argument) {
                        String arg = (String) argument;
                        if (arg.startsWith("wangwenjun") || arg.startsWith("wwj"))
                            return true;
                        else
                            throw new RuntimeException();
                    }
                }))).thenReturn("wangwenjun@gmail.com");
        try {
            whenNew(EmployeeService.class).withAnyArguments().thenReturn(employeeService);
            EmployeeController controller = new EmployeeController();
            String email = controller.getEmail("wangwnejun");
            assertEquals("wangwenjun@gmail.com", email);
            controller.getEmail("liudehua");
            fail("should not process to here.");
        } catch (Exception e) {
            assertTrue(e instanceof RuntimeException);
        }
    }



    @Test
    public void testGetEmail2() {
        EmployeeService employeeService =
                PowerMockito.mock(EmployeeService.class);
        PowerMockito.when(employeeService.findEmailByUserName(Mockito.anyString())).then(new Answer<String>(){
            @Override
            public String answer(InvocationOnMock invocation) throws
                    Throwable {
                String argument = (String) invocation.getArguments()[0];
                if("wangwenjun".equals(argument))
                    return "wangwenjun@gmail.com";
                else if("liudehua".equals(argument))
                    return "andy@gmail.com";
                throw new NullPointerException();
            }
        });
        try {
            PowerMockito.whenNew(EmployeeService.class).withNoArguments().thenReturn(employeeService);
            EmployeeController controller = new EmployeeController();
            String email = controller.getEmail("wangwenjun");
            assertEquals("wangwenjun@gmail.com",email);
            email = controller.getEmail("liudehua");
            assertEquals("andy@gmail.com",email);
            email = controller.getEmail("JackChen");
            fail("should not process to here.");
        } catch (Exception e) {
            assertTrue(e instanceof NullPointerException);
        }
    }


    @Test
    public void testExist() {
        try {
            EmployeeService employeeService = PowerMockito.spy(new EmployeeService());
            PowerMockito.doNothing().when(employeeService, "checkExist", "wangwenjun");
            boolean result = employeeService.exist("wangwenjun");
            assertTrue(result);
            PowerMockito.verifyPrivate(employeeService).invoke("checkExist","wangwenjun");
        } catch (Exception e) {
            e.printStackTrace();
            fail();
        }
    }

}